package com.yeskery.nut.bind.handler;

import com.yeskery.nut.annotation.web.RequestParam;
import com.yeskery.nut.bind.AnnotationBindObject;
import com.yeskery.nut.bind.BindObject;
import com.yeskery.nut.bind.FitValueHelper;
import com.yeskery.nut.bind.MethodParamHandler;
import com.yeskery.nut.core.Execution;
import com.yeskery.nut.core.MultipartFile;
import com.yeskery.nut.core.Request;
import com.yeskery.nut.scan.controller.AnnotationRequestMethodAttributes;
import com.yeskery.nut.util.BeanUtils;
import com.yeskery.nut.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.*;

/**
 * RequestParam方法参数对象处理接口
 * @author sprout
 * 2022-06-11 15:58
 */
public class RequestParamMethodParamHandler implements MethodParamHandler {

    @Override
    public AnnotationBindObject handle(AnnotationRequestMethodAttributes attributes, Annotation annotation, Parameter parameter, Request request, Execution execution) {
        RequestParam requestParam = (RequestParam) annotation;
        String name = requestParam.value();
        if (StringUtils.isEmpty(name)) {
            name = parameter.getName();
        }
        Type parameterizedType = parameter.getParameterizedType();
        if (BeanUtils.isCollectionOrArrayDependBean(parameterizedType)) {
            boolean isArray = BeanUtils.isArrayDependBean(parameterizedType);
            Class<?> clazz = isArray ? BeanUtils.getArrayComponentType(parameterizedType) : BeanUtils.getDependBeanClass(parameterizedType);
            Collection<Object> values;
            if (isArray) {
                values = new ArrayList<>();
            } else {
                Class<?> typeClass = BeanUtils.getDependBeanType(parameterizedType);
                if (typeClass.isAssignableFrom(List.class)) {
                    values = new ArrayList<>();
                } else if (typeClass.isAssignableFrom(Set.class)) {
                    values = new HashSet<>();
                } else {
                    values = new ArrayList<>();
                }
            }
            if (clazz == null) {
                return new AnnotationBindObject(new BindObject(null, true),
                        RequestParam.class, requestParam.required(), requestParam.value());
            }

            if (clazz.isAssignableFrom(MultipartFile.class)) {
                values.addAll(request.getFiles(name));
                return new AnnotationBindObject(new BindObject(isArray ? values.toArray((Object[]) Array.newInstance(clazz, 0)) : values, values.isEmpty()),
                        RequestParam.class, requestParam.required(), requestParam.value());
            }
            List<String> stringValues = request.getParameters(name);
            if (stringValues == null) {
                stringValues = new ArrayList<>();
            }
            if (stringValues.isEmpty() && !StringUtils.isEmpty(requestParam.defaultValue())) {
                stringValues.add(requestParam.defaultValue());
            }
            for (String stringValue : stringValues) {
                values.add(FitValueHelper.getInstance().getFitParamValue(name, stringValue, clazz).getData());
            }
            return new AnnotationBindObject(new BindObject(isArray ? values.toArray((Object[]) Array.newInstance(clazz, 0)) : values, values.isEmpty()),
                    RequestParam.class, requestParam.required(), requestParam.value());
        } else {
            if (parameter.getType().isAssignableFrom(MultipartFile.class)) {
                MultipartFile multipartFile = request.getFile(name);
                return new AnnotationBindObject(new BindObject(multipartFile, multipartFile == null),
                        RequestParam.class, requestParam.required(), requestParam.value());
            }
            String value = request.getParameter(name);
            if (StringUtils.isEmpty(value) && !StringUtils.isEmpty(requestParam.defaultValue())) {
                value = requestParam.defaultValue();
            }
            return new AnnotationBindObject(FitValueHelper.getInstance().getFitParamValue(name, value, parameter.getType()),
                    RequestParam.class, requestParam.required(), requestParam.value());
        }
    }
}
